package fybug.nulll.pdstream;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.ref.SoftReference;

import fybug.nulll.pdfunctionlibrary.Annotations.MaybeStop;
import fybug.nulll.pdfunctionlibrary.Processing.Err.Stop;
import fybug.nulll.pdfunctionlibrary.Util.DataContainer;
import fybug.nulll.pdfunctionlibrary.Util.Processing.Arrarys;
import fybug.nulll.pdstream.Interface.UpdateSize;
import fybug.nulll.pdstream.Source.StreamSource;

import static fybug.nulll.pdfunctionlibrary.Processing.Check.equalsFidle;
import static fybug.nulll.pdfunctionlibrary.Util.Processing.Arrarys.conversionArrayType;
import static fybug.nulll.pdstream.to.to;
/**
 * <h2>流操作器.</h2>
 * <pre>
 * <b>该类不允许直接构造,请使用其子类</b>
 *
 * 提供一个存放操作源的容器
 * 并可复用和关闭
 *
 * <b>提供流转化和包装服务</b>
 * </pre>
 *
 * @param <T> 操作流类型
 * @param <E> 输出数据类型
 *
 * @author fybug
 * @version 0.1.8
 * @see StreamSource
 * @see DataContainer
 * @see BufferedInputStream
 * @see BufferedOutputStream
 * @see BufferedReader
 * @see BufferedWriter
 * @see MaybeStop
 * @since JDK 1.8
 */
@SuppressWarnings( "all" )
public
class StreamOperator<T extends Closeable, E> extends DataContainer<StreamSource<T, E>> {
    protected
    StreamOperator() {super(null);}

    @Override
    protected
    boolean consistent(@NotNull final Object o) {
        @NotNull final StreamOperator obj = (StreamOperator) o;
        // 检查操作源
        return equalsFidle(getValue(), obj.getValue());
    }

    @Override
    public
    int hashCode()
    { return (getClass().hashCode() + super.hashCode()) << 5; }

    /*
     * MainSource
     */

    /**
     * <p>绑定操作源.</p>
     *
     * @param r 要作为操作器的数据来源的操作源类
     *
     * @return this
     */
    @NotNull
    protected
    StreamOperator<T, E> binSource(@Nullable final StreamSource<T, E> r)
    { return (StreamOperator<T, E>) setValue(r); }

    /**
     * <p>获取绑定的操作源.</p>
     *
     * @return this
     */
    @NotNull
    @MaybeStop
    public final
    StreamSource<T, E> source() { return getValue(); }

    /** 片段更新请求方法的软引用 */
    @NotNull protected volatile SoftReference<UpdateSize> bufferModer = new SoftReference<>(null);

    /**
     * <p>检查片段更新请求方法对象缓存.</p>
     *
     * @return 获取的检查对象缓存
     */
    @NotNull
    protected
    UpdateSize checkUpSize() {
        @NotNull UpdateSize updateSize;
        synchronized ( this ){
            updateSize = (UpdateSize) bufferModer.get(); // 获取当前对象
            if (updateSize == null)
                // 被清除
                bufferModer = new SoftReference<>(updateSize = i -> i);
        }
        return updateSize;
    }

    /*
     * 释放
     */

    /**
     * <p>清空该类中的引用.</p>
     * <pre>
     * 仅清空该类,但不关闭其中的可关闭对象
     * 清空后该对象仍可复用
     * </pre>
     */
    @Override
    public
    void clean() { super.clean(); }

    /**
     * <p>释放该类的资源.</p>
     * <pre>
     * 清空该类并关闭该类中的所有资源
     * 释放后仍可复用
     * </pre>
     */
    @Override
    public
    void free() {
        try {
            // 关闭源
            source().close();
        } catch ( Stop ignored ) {
        }
        clean();
    }

    /**
     * <p>彻底关闭该类.</p>
     * <pre>
     * 清除并关闭该类中的所有数据
     * 清除后不可再复用
     * </pre>
     */
    @Override
    public
    void close() { super.close(); }

    /*
     * BytesToBuffer
     */

    /**
     * <p>包装为缓冲读取流.</p>
     *
     * @param inputStream 要包装的字节读取流
     * @param bufferSize  缓冲大小 (无视错误)
     *
     * @return 包装着该流的缓冲读取流
     */
    @NotNull
    public static
    BufferedInputStream toBufferStream(@NotNull final InputStream inputStream, final int bufferSize)
    {
        if (inputStream instanceof BufferedInputStream)
            return (BufferedInputStream) inputStream;
        return new BufferedInputStream(inputStream, bufferSize <= 0 ? 1 : bufferSize);
    }

    /**
     * <p>批量包装为缓冲读取流.</p>
     *
     * @param bufferSize  缓冲大小 (无视错误)
     * @param inputStream 要包装的字节读取流
     *
     * @return 包装着该流的缓冲读取流
     */
    @NotNull
    public static
    BufferedInputStream[] toBufferStream(final int bufferSize,
            @NotNull final InputStream... inputStream)
    {
        return Arrarys.conversionArrayType(inputStream, o -> {
            if (o instanceof BufferedInputStream)
                return (BufferedInputStream) o;
            return new BufferedInputStream(o, bufferSize <= 0 ? 1 : bufferSize);
        }, BufferedInputStream.class);
    }

    /**
     * <p>包装为缓冲输出流.</p>
     *
     * @param inputStream 要包装的字节输出流
     * @param bufferSize  缓冲大小 (无视错误)
     *
     * @return 包装着该流的缓冲输出流
     */
    @NotNull
    public static
    BufferedOutputStream toBufferStream(@NotNull final OutputStream outputStream,
            final int bufferSize)
    {
        if (outputStream instanceof BufferedOutputStream)
            return (BufferedOutputStream) outputStream;
        return new BufferedOutputStream(outputStream, bufferSize <= 0 ? 1 : bufferSize);
    }

    /**
     * <p>批量包装为缓冲写入流.</p>
     *
     * @param bufferSize  缓冲大小 (无视错误)
     * @param inputStream 要包装的字节输出流
     *
     * @return 包装着该流的缓冲输出流
     */
    @NotNull
    public static
    BufferedOutputStream[] toBufferStream(final int bufferSize,
            @NotNull final OutputStream... outputStreams)
    {
        return Arrarys.conversionArrayType(outputStreams, outputStream -> {
            if (outputStream instanceof BufferedOutputStream)
                return (BufferedOutputStream) outputStream;
            return new BufferedOutputStream(outputStream, bufferSize <= 0 ? 1 : bufferSize);
        }, BufferedOutputStream.class);
    }

    /*
     * ToReader
     */

    /**
     * <p>将字节流转化为字符流.</p>
     * <p>需提供字符编码</p>
     *
     * @param inputStream 要转化的字节流
     * @param charname    字符编码
     *
     * @return 转化后的字符流
     */
    @NotNull
    public static
    Reader getReader(@NotNull final InputStream inputStream, @NotNull final String charname)
    {
        try {
            return new InputStreamReader(inputStream, charname);
        } catch ( UnsupportedEncodingException e ) {
            return new InputStreamReader(inputStream);
        }
    }

    /**
     * <p>将字节流组转化为字符流组.</p>
     * <p>需提供字符编码</p>
     *
     * @param charname    字符编码
     * @param inputStream 要转化的字节流
     *
     * @return 转化后的字符流
     */
    @NotNull
    public static
    Reader[] getReader(@NotNull final String charname, @Nullable InputStream... inputStreams)
    {
        return conversionArrayType(inputStreams, (InputStream in) -> {
            // 转化方法
            try {
                return new InputStreamReader(in, charname);
            } catch ( UnsupportedEncodingException e ) {
                return new InputStreamReader(in);
            }
        }, Reader.class);
    }

    /**
     * <p>包装为缓存读取流.</p>
     *
     * @param bufferSize 缓冲区大小
     * @param w          要包装的流
     *
     * @return 包装好的流
     */
    @NotNull
    public static
    BufferedReader toBufferStream(@NotNull final Reader w, final int bufferSize)
    {
        if (w instanceof BufferedReader)
            return (BufferedReader) w;
        return new BufferedReader(w, bufferSize <= 0 ? 1 : bufferSize);
    }

    /**
     * <p>批量包装为缓存读取流.</p>
     *
     * @param bufferSize 缓冲区大小
     * @param w          要包装的流
     *
     * @return 包装好的流
     */
    @NotNull
    public static
    BufferedReader[] toBufferStream(final int bufferSize, @Nullable final Reader... w) {
        return to(bufferSize, w, BufferedReader.class, (out, buff) -> {
            if (out instanceof BufferedReader)
                return (BufferedReader) out;
            return new BufferedReader(out, buff);
        });
    }

    /*
     * ToWriter
     */

    /**
     * <p>将字节流转化为字符流.</p>
     * <p>需提供字符编码</p>
     *
     * @param charname 转化用的字符编码
     * @param w        要转化的流
     *
     * @return 转化后的流
     */
    @NotNull
    public static
    Writer getWriter(@NotNull final String charname, @NotNull final OutputStream outputStream)
    {
        try {
            return new OutputStreamWriter(outputStream, charname);
        } catch ( UnsupportedEncodingException e ) {
            return new OutputStreamWriter(outputStream);
        }
    }

    /**
     * <p>将字节流组转化为字符流组.</p>
     * <p>需提供字符编码</p>
     *
     * @param charname 转化用的字符编码
     * @param w        要转化的流
     *
     * @return 转化后的流
     */
    @NotNull
    public static
    Writer[] getWriter(@NotNull final String charname, @Nullable OutputStream... outputStreams) {
        return conversionArrayType(outputStreams, out -> {
            // 转化方法
            try {
                return new OutputStreamWriter(out, charname);
            } catch ( UnsupportedEncodingException e ) {
                return new OutputStreamWriter(out);
            }
        }, Writer.class);
    }

    /**
     * <p>包装为缓存写入流.</p>
     *
     * @param bufferSize 缓冲区大小
     * @param w          要包装的流
     *
     * @return 包装好的流
     */
    @NotNull
    public static
    BufferedWriter toBufferStream(@NotNull final Writer w, final int bufferSize)
    {
        if (w instanceof BufferedWriter)
            return (BufferedWriter) w;
        return new BufferedWriter(w, bufferSize <= 0 ? 1 : bufferSize);
    }

    /**
     * <p>批量包装为缓存写入流.</p>
     *
     * @param bufferSize 缓冲区大小
     * @param w          要包装的流
     *
     * @return 包装好的流
     */
    @NotNull
    public static
    BufferedWriter[] toBufferStream(final int bufferSize, @Nullable final Writer... w) {
        return to(bufferSize, w, BufferedWriter.class, (out, bufferSize1) -> {
            if (out instanceof BufferedWriter)
                return (BufferedWriter) out;
            return new BufferedWriter(out, bufferSize1);
        });
    }
}
